package org.visionlibrary.image.filters.thresholding;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.acquisition.ImageFactory;
import org.visionlibrary.image.model.AbstractFilter;
import org.visionlibrary.image.model.FilterTools;


//TODO: Sprawdzic czy dziala poprawnie
public class MaximumEntropyHistogramSplitThreshold extends AbstractFilter {
	@Override
	public TiledImage applyFilter(TiledImage src, TiledImage dest) {
		if (null == src)
			throw new NullPointerException("Source image is null.");

		if (null == dest)
			dest = (new ImageFactory()).createCompatibleImage(src);

		int maxX = src.getWidth();
		int maxY = src.getHeight();

		int threshold = 0;

		for (int ch = 0; ch < src.getNumBands(); ch++) {
			int[] histogram = FilterTools.getHistogram(src, ch);

			double[] normalizedHistogram = new double[histogram.length];
			double[] probability = new double[histogram.length];

			double sum = 0.0;
			for (int i = 0; i < histogram.length; i++)
				sum += ((double) histogram[i]);

			for (int i = 0; i < histogram.length; i++)
				normalizedHistogram[i] = ((double) histogram[i]) / sum;

			probability[0] = normalizedHistogram[0];
			for (int i = 1; i < histogram.length; i++)
				probability[i] = probability[i - 1] + normalizedHistogram[i];

			final double epsilon = Double.MIN_VALUE;
			double[] hB = new double[histogram.length];
			double[] hW = new double[histogram.length];
			for (int t = 0; t < histogram.length; t++) {
				if (probability[t] > epsilon) {
					double hhB = 0;
					for (int i = 0; i <= t; i++) {
						if (normalizedHistogram[i] > epsilon)
							hhB -= normalizedHistogram[i]
									/ probability[t]
									* Math.log(normalizedHistogram[i]
											/ probability[t]);
					}
					hB[t] = hhB;
				} else {
					hB[t] = 0;
				}

				double pTW = 1 - probability[t];
				if (pTW > epsilon) {
					double hhW = 0;
					for (int i = t + 1; i < histogram.length; ++i) {
						if (normalizedHistogram[i] > epsilon)
							hhW -= normalizedHistogram[i] / pTW
									* Math.log(normalizedHistogram[i] / pTW);
					}
					hW[t] = hhW;
				} else {
					hW[t] = 0;
				}
			}

			double jMax = hB[0] + hW[0];
			for (int t = 1; t < histogram.length; ++t) {
				double j = hB[t] + hW[t];
				if (j > jMax) {
					jMax = j;
					threshold = t;
				}
			}

			for (int x = 0; x < maxX; x++)
				for (int y = 0; y < maxY; y++) {
					int newPixelVal = src.getSample(x, y, ch);
					if (newPixelVal > threshold) {
						dest.setSample(x, y, ch, 255);
					} else {
						dest.setSample(x, y, ch, 0);
					}

				}
		}

		return dest;
	}
}
